package net.edwardstx.brian.rpn.types;

import net.edwardstx.brian.rpn.RPNStackItem;
import net.edwardstx.brian.rpn.exception.InvalidArguments;
import net.edwardstx.brian.rpn.exception.InvalidSyntax;
import net.edwardstx.brian.rpn.type.annotations.RPNOperation;

public class RPNString implements RPNStackItem, Comparable<RPNString> {
	public static final String TYPE_NAME = "String";
	public static final Type<RPNString> TYPE = new Type<RPNString>(TYPE_NAME,RPNString.class);
	
	private final String value;
	
	public RPNString(String value) {
		this.value = value;
	}
	
	
	public static RPNString parse(String value)throws InvalidSyntax{
		value = value.trim();
		try{
			if(value.startsWith("\"") && value.endsWith("\"")){
				return new RPNString(value.substring(1, value.length() - 1));
			} else 
				throw new InvalidSyntax();
		} catch (Exception e){
			throw new InvalidSyntax();
		}
	}
	
	public String getValue() {
		return value;
	}


	@RPNOperation("+")
	public static RPNString concatenate(RPNString l_0, RPNStackItem l_1 ){
		String other;
		if(l_1 instanceof RPNString){
			other = ((RPNString)l_1).value;
		} else {
			other = l_1.toString();
		}
		return new RPNString(other + l_0.value );
	}
	
	@RPNOperation("+")
	public static RPNString concatenate(RPNStackItem l_0, RPNString l_1 ){
		String other;
		if(l_0 instanceof RPNString){
			other = ((RPNString)l_0).value;
		} else {
			other = l_0.toString();
		}
		return new RPNString(l_1.value + other);
	}
	
	@RPNOperation("toString")
	public static RPNString toString(RPNStackItem l_0){
		if(l_0 instanceof RPNString)
			return (RPNString) l_0;
		return new RPNString(l_0.toString());
	}
	
	@RPNOperation("HEAD")
	public static RPNString head(RPNString l_0){
		if(l_0.value.length() == 0)
			return l_0;
		return new RPNString(l_0.value.substring(0, 1));
	}
	
	@RPNOperation("TAIL")
	public static RPNString tail(RPNString l_0){
		if(l_0.value.length() == 0)
			return l_0;
		return new RPNString(l_0.value.substring(1));
	}
	
	@RPNOperation("SUB")
	public static RPNString sub(RPNInteger l_0, RPNInteger l_1, RPNString l_2){
		try{
			return new RPNString(l_2.value.substring(l_0.value.intValue(),l_1.value.intValue()));
		} catch ( IndexOutOfBoundsException e){
			throw new InvalidArguments();
		}
	}
	
	@RPNOperation("SIZE")
	public static RPNInteger size(RPNString l_0){
		return new RPNInteger(l_0.value.length());
	}
	
	@RPNOperation("POS")
	public static RPNInteger pos(RPNString l_0, RPNString l_1){
		return new RPNInteger(l_1.value.indexOf(l_0.value));
	}

	@Override
	public Type<RPNString> getAssociatedType() {
		return TYPE;
	}

	@Override
	public int compareTo(RPNString o) {
		return value.compareTo(o.value);
	}
	
	
	@Override
	public String toString(){
		return '"' + value + '"';
	}

}
